/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.task.support.scripting;

import cn.easyplatform.EasyPlatformWithLabelKeyException;
import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Mirror;
import cn.easyplatform.lang.Streams;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.web.task.BackendException;
import cn.easyplatform.web.task.event.ContinueException;
import cn.easyplatform.web.task.event.PauseException;
import cn.easyplatform.web.utils.WebUtils;
import org.apache.commons.lang3.StringUtils;
import org.mozilla.javascript.*;

import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
final public class ScriptUtils {

    private static class Parser {

        boolean beginQuotes = false;

        boolean beginDbQuotes = false;

        String parseScript(List<String> includes, String script) {
            char[] cs = script.toCharArray();
            int len = cs.length;
            StringBuilder sb = new StringBuilder(" ");
            StringBuilder tmp = new StringBuilder();
            for (int i = 0; i < len; i++) {
                if (cs[i] == '"') {
                    if (i > 1 && cs[i - 1] == '\\' && cs[i - 2] != '\\') {// 转义符不处理
                    } else
                        beginDbQuotes = !beginDbQuotes;
                }
                if (!beginDbQuotes && cs[i] == '\'') {
                    if (i > 1 && cs[i - 1] == '\\' && cs[i - 2] != '\\') {// 转义符不处理
                    } else
                        beginQuotes = !beginQuotes;
                }
                if (!beginQuotes && !beginDbQuotes) {
                    if (i < len - 1) {
                        if (cs[i] == '-' && cs[i + 1] == '>') {// 处理->
                            sb.append("$");
                            i++;
                        } else if (cs[i] == '/' && cs[i + 1] == '/') {// 处理注解符号//
                            while (i < len) {
                                sb.append(cs[i]);
                                if (cs[i] == '\n') {
                                    break;
                                }
                                i++;
                            }
                        } else if (cs[i] == '/' && cs[i + 1] == '*') {// 处理注解符号/*和*/
                            while (i < len) {
                                sb.append(cs[i]);
                                if (cs[i] == '*' && i < len - 1 && cs[i + 1] == '/') {
                                    break;
                                }
                                i++;
                            }
                        } else if ((cs[i] == '$' || cs[i] == '@')
                                && (Character.isLetterOrDigit(cs[i + 1]) || cs[i + 1] == '_')) {
                            char c = cs[i];
                            tmp.setLength(0);
                            i++;
                            Character bk = null;
                            while (i < len) {
                                if (!Character.isLetterOrDigit(cs[i])
                                        && cs[i] != '_') {
                                    bk = cs[i];
                                    break;
                                } else
                                    tmp.append(cs[i]);
                                i++;
                            }
                            String name = tmp.toString();
                            tmp.setLength(0);
                            boolean isEquals = false;
                            int index = i;
                            while (index < len) {
                                if (cs[index] == ';' || cs[index] == '\n')
                                    break;
                                if (!isEquals) {
                                    if (Character.isLetter(cs[index]))
                                        break;
                                    if (cs[index] == '=' && index < len - 1
                                            && cs[index + 1] != '='
                                            && cs[index - 1] != '='
                                            && cs[index - 1] != '!'
                                            && cs[index - 1] != '>'
                                            && cs[index - 1] != '<') {
                                        isEquals = true;
                                    }
                                } else
                                    tmp.append(cs[index]);
                                index++;
                            }
                            int size = sb.length() - 1;
                            if (sb.charAt(size) == '$')
                                sb.deleteCharAt(size);
                            else
                                sb.append("$");
                            if (isEquals) {
//                                sb.append(".setValue('").append(name).append("',")
//                                        .append(parseScript(includes, tmp.toString())).append(");");
                                sb.append(".setValue('").append(name).append("',")
                                        .append(parseScript(includes, tmp.toString())).append(",'")
                                        .append(c).append("');");
                                i = index;
                            } else if (!name.equals("easyplatform")) {
//                                sb.append(".getValue('").append(name).append("')");
                                sb.append(".getValue('").append(name).append("','")
                                        .append(c).append("')");
                                if (bk != null)
                                    sb.append(bk);
                            } else
                                sb.append(name).append(bk);
                        } else if (cs[i] == 'i' && i < len - 7 && cs[i + 1] == 'm'
                                && cs[i + 2] == 'p' && cs[i + 3] == 'o'
                                && cs[i + 4] == 'r' && cs[i + 5] == 't'
                                && cs[i + 6] == ' ') {// 处理import xxx.xx.xxxx;
                            i += 7;
                            tmp.setLength(0);
                            char c = ' ';
                            while (i < len) {
                                if (cs[i] == ';')
                                    break;
                                else if (cs[i] != ' ') {
                                    tmp.append(cs[i]);
                                    if (cs[i] == '.')
                                        c = cs[i + 1];
                                }
                                i++;
                            }
                            if (Character.isUpperCase(c))
                                sb.append("importClass(Packages.").append(tmp).append(");");
                            else
                                sb.append("importPackage(Packages.").append(tmp)
                                        .append(");");
                        } else if (cs[i] == '#' && i < len - 9 && cs[i + 1] == 'i'
                                && cs[i + 2] == 'n' && cs[i + 3] == 'c'
                                && cs[i + 4] == 'l' && cs[i + 5] == 'u'
                                && cs[i + 6] == 'd' && cs[i + 7] == 'e'
                                && (cs[i + 8] == ' ' || cs[i + 8] == '(')) {//#include color.js，如果不以.js结束，取参数表id
                            i += 9;
                            tmp.setLength(0);
                            while (i < len) {
                                if (cs[i] == ';' || cs[i] == ')')
                                    break;
                                else if (cs[i] != ' ')
                                    tmp.append(cs[i]);
                                i++;
                            }
                            String id = tmp.toString().trim();
                            includes.add(WebUtils.getScriptContent(id));
                        } else
                            sb.append(cs[i]);
                    } else
                        sb.append(cs[i]);
                } else
                    sb.append(cs[i]);
            }
            return sb.toString();
        }

    }

    final static String[] parse(String script) {
        List<String> includes = new ArrayList<String>();
        String expr = new Parser().parseScript(includes, script);
        includes.add(0, expr);
        String[] tmp = new String[includes.size()];
        includes.toArray(tmp);
        includes = null;
        return tmp;
    }

    final static RuntimeException handleScriptException(RhinoException ex) {
        if (ex instanceof JavaScriptException) {
            Object val = ((JavaScriptException) ex).getValue();
            if ("NativeError".equals(val.getClass().getSimpleName()))
                ex = (RhinoException) Mirror.me(val).getEjecting("stackProvider").eject(val);
        }
        int line = ex.lineNumber();
        for (ScriptStackElement e : ex.getScriptStack()) {
            if (e.functionName == null) {
                line = e.lineNumber;
                break;
            }
        }
        String msg = null;
        if (ex instanceof WrappedException) {
            Throwable t = ((WrappedException) ex).getWrappedException();
            if (t instanceof BackendException) {
                BackendException e = (BackendException) t;
                e.setLine(line);
                throw e;
            }
            if (t instanceof PauseException) {
                PauseException e = (PauseException) t;
                e.setLine(line);
                throw e;
            }
            if (t instanceof ContinueException)
                throw (ContinueException) t;
            if (t instanceof EasyPlatformWithLabelKeyException)
                throw (EasyPlatformWithLabelKeyException) t;
            if (t instanceof EventExitException)
                throw (EventExitException) t;
            Throwable we = ((WrappedException) ex).getWrappedException();
            we.printStackTrace();
            msg = we.getMessage();
            return new ScriptEvalException(msg, we, line);
        } else
            msg = ex.getMessage();
        return new ScriptEvalException(msg, ex, line);
    }

    public final static Map<String, String> getMapping(String expr,
                                                       String targetId) {
        Map<String, String> mapping = new HashMap<String, String>();
        char[] cs = expr.toCharArray();
        int len = cs.length;
        boolean beginQuotes = false;
        boolean beginDbQuotes = false;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < len; i++) {
            if (cs[i] == '"')
                beginDbQuotes = !beginDbQuotes;
            if (cs[i] == '\'')
                beginQuotes = !beginQuotes;
            if (!beginQuotes && !beginDbQuotes) {
                if (i < len - 1) {
                    if (cs[i] == '/' && cs[i + 1] == '/') {// 处理注解符号//
                        while (i < len) {
                            if (cs[i] == '\n') {
                                break;
                            }
                            i++;
                        }
                    } else if (cs[i] == '/' && cs[i + 1] == '*') {// 处理注解符号/*和*/
                        while (i < len) {
                            if (cs[i] == '*' && i < len - 1 && cs[i + 1] == '/') {
                                break;
                            }
                            i++;
                        }
                    } else if (cs[i] == '$'
                            && (Character.isLetterOrDigit(cs[i + 1]) || cs[i + 1] == '_')) {
                        sb.setLength(0);
                        i++;
                        while (i < len) {
                            if (!Character.isLetterOrDigit(cs[i])
                                    && cs[i] != '_') {
                                break;
                            } else
                                sb.append(cs[i]);
                            i++;
                        }
                        String name = sb.toString();
                        sb.setLength(0);
                        boolean isEquals = false;
                        int index = i;
                        while (index < len) {
                            if (cs[index] == ';' || cs[index] == '\n')
                                break;
                            if (!isEquals) {
                                if (Character.isLetter(cs[index]))
                                    break;
                                if (cs[index] == '=' && index < len - 1
                                        && cs[index + 1] != '='
                                        && cs[index - 1] != '='
                                        && cs[index - 1] != '!') {
                                    isEquals = true;
                                }
                            } else
                                sb.append(cs[index]);
                            index++;
                        }
                        if (isEquals) {
                            String src = sb.toString().trim();
                            if (src.startsWith("@")) {
                                mapping.put(name, src.substring(1));
                                if (targetId != null && name.equals(targetId))
                                    break;
                            }
                            i = index;
                        }
                    }
                }
            }
        }
        return mapping;
    }

    public static void main(String[] args) {
        try {
            String driver = "com.mysql.jdbc.Driver";
            String url = "jdbc:mysql://localhost:3306/granite_biz?useUnicode=true&amp;characterEncoding=UTF-8";
            String username = "granite";
            String password = "1qazxsw2";
            Class.forName(driver); //classLoader,加载对应驱动
            Connection conn = (Connection) DriverManager.getConnection(url, username, password);
            PreparedStatement pstmt0 = conn.prepareStatement("INSERT into bus_line (coord) values(?)");
            //PreparedStatement pstmt1 = conn.prepareStatement("INSERT into bus_line_station (bus_id,station) values(?,?)");
            String str = Lang.readAll(Streams.fileInr(new File("D:\\MyWork\\epclouds\\easyplatform-web\\WebRoot\\test.data")));
            //String str1 = Lang.readAll(Streams.fileInr(new File("D:\\MyWork\\epclouds\\easyplatform-web\\WebRoot\\test1.data")));
            //String str2 = Lang.readAll(Streams.fileInr(new File("D:\\MyWork\\epclouds\\easyplatform-web\\WebRoot\\test2.data")));
            String[] data = StringUtils.substringsBetween(str, "[", "]");
            //String[] data1 = str1.split(",");
            //String[] data2 = str2.split(",");
            for (int i = 0; i < data.length; i++) {
                if (Strings.isBlank(data[i]))
                    continue;
                String[] vals = data[i].split(",");
                pstmt0.setString(1, data[i]);
//                pstmt0.setInt(2, Integer.parseInt(vals[1]));
                pstmt0.addBatch();
//                for (int j = 2; j < vals.length; j++) {
//                    pstmt1.setInt(1, i + 1);
//                    pstmt1.setInt(2, Integer.parseInt(vals[j]));
//                    pstmt1.addBatch();
//                }
            }
            pstmt0.executeBatch();
            pstmt0.close();
//            pstmt1.executeBatch();
//            pstmt1.close();
            conn.close();
            /**
             //Class clazz = Class.forName("cn.easyplatform.web.ext.echarts.lib.graphic.Graphic");
             List<Class<?>> list = ClassUtils.getClasses("cn.easyplatform.web.ext.echarts.lib.series");
             List<String> tmp = new ArrayList<String>();
             List<Field> fields = new ArrayList<Field>();
             //            for (Field f : clazz.getDeclaredFields()) {
             //                if (!tmp.contains(f.getName())) {
             //                    fields.add(f);
             //                    tmp.add(f.getName());
             //                }
             //            }
             for (Class c : list) {
             for (Field f : c.getDeclaredFields()) {
             if (!tmp.contains(f.getName())) {
             fields.add(f);
             tmp.add(f.getName());
             }
             }
             }
             for (Field f : fields) {
             System.out.println("private " + f.getType().getSimpleName() + " " + f.getName() + ";");
             }
             System.out.println(DateFormats.format(new Date(), false));
             System.out
             .println(parse("if($aa.substring(1,3).equals('aa'))$var='';"));*/
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
